
#include <BStyle>
#include <BPainter>
#include <BThread>
#include <BButton>
#include <BMouseEvent>
#include <BEvent>
#include <BApplication>
#include <BSystem>
#include <BScreen>
#include <BMainWindow>
#include "member_BMainWindow.h"
#include "member_BWidget.h"
#include "IWindow.h"

#define member						(*(member_BMainWindow*)_ptr)
#define member_allocate()			_ptr = new member_BMainWindow(this)
#define member_release()			delete (member_BMainWindow*)_ptr

using namespace BWE;

BMainWindow::BMainWindow(BWidget* parent) : BWidget(parent)
{
	member_allocate();
	this->setBorder(5);
	this->addTitleButton(Button_Minimize);
	this->addTitleButton(Button_Maximize);
	this->addTitleButton(Button_Close);
	if (parent == 0)
	{
		BScreen* screen = BSystem::GetScreen(BCursor::GetPos());
		BSize size = screen->size() * 0.76f;
		this->setSize(size);
	}
}
BMainWindow::BMainWindow(const BString& title, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	this->setTitle(title);
	this->setBorder(5);
	this->addTitleButton(Button_Minimize);
	this->addTitleButton(Button_Maximize);
	this->addTitleButton(Button_Close);
	if (parent == 0)
	{
		BScreen* screen = BSystem::GetScreen(BCursor::GetPos());
		BSize size = screen->size() * 0.76f;
		this->setSize(size);
	}
}
BMainWindow::~BMainWindow()
{
	member_release();
}

bool BMainWindow::setTitle(const BString& title)
{
	if (BWidget::setTitle(title))
	{
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BMainWindow::setTitleIcon(BIcon* titleIcon)
{
	if (BWidget::setTitleIcon(titleIcon))
	{
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
void BMainWindow::setFrameless(bool frameless)
{
	BWidget::setFrameless(frameless);
	member.dirty = true;
	this->fresh();
}

BButton* BMainWindow::addTitleButton(Button button)
{
	for (int i = 0; i < member.buttonLayout->count(); i++)
	{
		BWidget* button = member.buttonLayout->widget(i);
		if (button->asset() == button)
			return (BButton*)button;
	}
	BButton* btn = new BButton(this);
	btn->setAsset(button);
	if (Graph graph = member.ButtonGraph(button))
	{
		btn->setGraph(graph);
		btn->setForm(Form_IconAlone);
	}
	if (const char* name = member.ButtonName(button))
	{
		btn->setName(name);
	}
	member.buttonLayout->addWidget(btn);
	member.connect(btn, Signal_Clicked, &member_BMainWindow::slotTitleButtonClicked);
	return btn;
}
bool BMainWindow::addTitleButton(BButton* button)
{
	if (!button)
		return false;
	if (!member.buttonLayout->contain(button))
	{
		this->addChild(button);
		member.buttonLayout->addWidget(button);
		member.connect(button, Signal_Clicked, &member_BMainWindow::slotTitleButtonClicked);
	}
	return true;
}

BButton* BMainWindow::insertTitleButton(int pos, Button button)
{
	if (pos < 0 || pos > member.buttonLayout->count())
		return 0;
	for (int i = 0; i < member.buttonLayout->count(); i++)
	{
		BWidget* button = member.buttonLayout->widget(i);
		if (button->asset() == button)
			return (BButton*)button;
	}
	BButton* btn = new BButton(this);
	btn->setAsset(button);
	if (Graph graph = member.ButtonGraph(button))
	{
		btn->setGraph(graph);
		btn->setForm(Form_IconAlone);
	}
	if (const char* name = member.ButtonName(button))
	{
		btn->setName(name);
	}
	member.buttonLayout->insertWidget(pos, btn);
	member.connect(btn, Signal_Clicked, &member_BMainWindow::slotTitleButtonClicked);
	return btn;
}
bool BMainWindow::insertTitleButton(int pos, BButton* button)
{
	if (!button)
		return false;
	if (pos < 0 || pos > member.buttonLayout->count())
		return 0;
	if (!member.buttonLayout->contain(button))
	{
		this->addChild(button);
		member.buttonLayout->insertWidget(pos, button);
		member.connect(button, Signal_Clicked, &member_BMainWindow::slotTitleButtonClicked);
	}
	return true;
}

bool BMainWindow::removeTitleButton(Button button)
{
	for (int i = 0; i < member.buttonLayout->count(); i++)
	{
		BWidget* widget = member.buttonLayout->widget(i);
		if (widget->asset() == button)
		{
			member.disconnect(widget);
			this->removeChild(widget);
			member.buttonLayout->remove(widget);
			member.dirty = true;
			this->fresh();
			return true;
		}
	}
	return false;
}
bool BMainWindow::removeTitleButton(BButton* button)
{
	for (int i = 0; i < member.buttonLayout->count(); i++)
	{
		BWidget* widget = member.buttonLayout->widget(i);
		if (widget == button)
		{
			member.disconnect(widget);
			this->removeChild(widget);
			member.buttonLayout->remove(widget);
			member.dirty = true;
			this->fresh();
			return true;
		}
	}
	return false;
}
void BMainWindow::clearTitleButtons()
{
	if (member.buttonLayout->count())
	{
		for (int i = 0; i < member.buttonLayout->count(); i++)
		{
			BWidget* widget = member.buttonLayout->widget(i);
			member.disconnect(widget);
			this->removeChild(widget);
		}
		member.buttonLayout->clear();
		member.dirty = true;
		this->fresh();
	}
}

int BMainWindow::titleButtonCount() const
{
	return member.buttonLayout->count();
}
const BButton* BMainWindow::titleButton(int index) const
{
	return (BButton*)member.buttonLayout->widget(index);
}

void BMainWindow::close()
{
	BEvent closeEvent(Event_Close);
	widget_member(this)->procEvent(closeEvent);
}

bool BMainWindow::event(const BEvent& event)
{
	if (event.type() == Event_Move)
	{
		member.moved = true;
	}
	return BWidget::event(event);
}

void BMainWindow::closeEvent(const BEvent& event)
{
	emit(Signal_Close);
	BWidget::closeEvent(event);
}

void BMainWindow::showEvent(const BEvent& event)
{
	if (this->parent() == 0 || widget_member(this)->upperLayout == 0)
	{
		BRect upperRect;
		if (this->parent())
		{
			upperRect = this->parent()->size();
		}
		else
		{
			if (widget_member(this)->window)
			{
				BScreen* screen = BSystem::GetScreen(BCursor::GetPos());
				upperRect = screen->rect();
			}
			else if (widget_member(this)->pixmap)
			{
				upperRect = widget_member(this)->pixmap->size();
			}
		}
		if (member.dirty)
		{
			member.freshRects();
			member.dirty = false;
		}
		BRect rect = this->rect();
		BSize hsize = this->sizeHint();
		if (rect.width() < hsize.width())
			rect.setWidth(hsize.width());
		if (rect.height() < hsize.height())
			rect.setHeight(hsize.height());
		rect = upperRect.wrap(rect);
		if (member.moved == false)
			rect = upperRect.align(Align_Center, rect.size());
		this->setRect(rect);
	}
	BWidget::showEvent(event);
}
void BMainWindow::resizeEvent(const BEvent& event)
{
	member.dirty = true;
	BWidget::resizeEvent(event);
}

void BMainWindow::styleEvent(const BEvent& event)
{
	const BStyle* style = this->realStyle();

	if (const BStyle* titleStyle = style->sub("title"))
	{
		const BValue& leftValue = titleStyle->value(Value_Margin_Left);
		if (leftValue.valid())
			member.titleMargin.left() = leftValue;

		const BValue& topValue = titleStyle->value(Value_Margin_Top);
		if (topValue.valid())
			member.titleMargin.top() = topValue;

		const BValue& rightValue = titleStyle->value(Value_Margin_Right);
		if (rightValue.valid())
			member.titleMargin.right() = rightValue;

		const BValue& bottomValue = titleStyle->value(Value_Margin_Bottom);
		if (bottomValue.valid())
			member.titleMargin.bottom() = bottomValue;

		const BValue& alignValue = titleStyle->value(Value_Align);
		if (alignValue.valid())
			member.titleAlign = alignValue;

		const BValue& spaceValue = titleStyle->value(Value_Space);
		if (spaceValue.valid())
			member.titleSpace = spaceValue;

		const BValue& iconSizeValue = titleStyle->value(Value_Icon_Size);
		if (iconSizeValue.valid())
		{
			member.titleIconSize = iconSizeValue;
			if (this->perch(Part_Top) < member.titleIconSize.height())
				this->setPerch(Part_Top, member.titleIconSize.height());
		}
	}
	if (const BStyle* buttonStyle = style->sub("button"))
	{
		const BValue& spaceValue = buttonStyle->value(Value_Space);
		if (spaceValue.valid())
			member.buttonLayout->setSpacing(spaceValue);

		const BValue& leftValue = buttonStyle->value(Value_Margin_Left);
		if (leftValue.valid())
			member.buttonLayout->setMargin(Part_Left, leftValue);

		const BValue& topValue = buttonStyle->value(Value_Margin_Top);
		if (topValue.valid())
			member.buttonLayout->setMargin(Part_Top, topValue);

		const BValue& rightValue = buttonStyle->value(Value_Margin_Right);
		if (rightValue.valid())
			member.buttonLayout->setMargin(Part_Right, rightValue);

		const BValue& bottomValue = buttonStyle->value(Value_Margin_Bottom);
		if (bottomValue.valid())
			member.buttonLayout->setMargin(Part_Bottom, bottomValue);
	}
	member.dirty = true;
}
void BMainWindow::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
}
void BMainWindow::paintEvent(const BEvent& event)
{
	BPainter painter(this);
	painter.drawBackground();
	painter.drawPerch();
	painter.drawTitle(State_Normal);

	if (widget_member(this)->pixmap || widget_member(this)->parent || widget_member(this)->frameless)
	{
		if (this->title().size())
		{
			if (member.pressed)
				painter.setColor(Color_Title_Text_Pressed);
			else if (this->hovered())
				painter.setColor(Color_Title_Text_Hovered);
			else if (this->actived())
				painter.setColor(Color_Title_Text_Actived);
			else
				painter.setColor(Color_Title_Text);
			if (member.tr_title.size())
				painter.drawText(member.textRect, member.tr_title);
			else
				painter.drawText(member.textRect, this->title());
		}

		painter.setLineSmooth(true);
		painter.setLineWidth(2);

		BIcon* titleIcon = this->titleIcon();
		if (titleIcon)
		{
			BImage* image = titleIcon->image(State_Normal);
			if (image)
				painter.drawImage(member.iconRect, image);
		}
	}

	painter.drawBorder();
	painter.drawMargin();
}

void BMainWindow::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mouseEnterEvent(mouseEvent);
}
void BMainWindow::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mouseLeaveEvent(mouseEvent);
}

void BMainWindow::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (widget_member(this)->pixmap || widget_member(this)->parent || widget_member(this)->frameless)
	{
		BPoint pos = mouseEvent.pos();
		if (mouseEvent.button() == Button_Left && (member.titleRect.contain(pos) || member.resizePart))
		{
			member.pressed = true;
			member.pressedPos = mouseEvent.globalPos();
			member.pressedRect = this->rect();
			this->fresh();
		}
	}
	BWidget::mousePressEvent(mouseEvent);
}
void BMainWindow::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (widget_member(this)->pixmap || widget_member(this)->parent || widget_member(this)->frameless)
	{
		if (mouseEvent.button() == Button_Left)
		{
			member.pressed = false;
			member.pressedPos.reset();
			member.pressedRect.reset();
			this->fresh();
		}
	}
	BWidget::mouseReleaseEvent(mouseEvent);
}
void BMainWindow::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (widget_member(this)->upperLayout)
		return;
	if (widget_member(this)->pixmap || widget_member(this)->parent || widget_member(this)->frameless)
	{
		if (member.pressed && member.resizePart)
		{
			BPoint gpos = mouseEvent.globalPos();
			BPoint offset = gpos - member.pressedPos;
			BRect rect = member.pressedRect;
			if (member.resizePart & Part_Left)
				rect.left() = rect.left() + offset.x();
			if (member.resizePart & Part_Top)
				rect.top() = rect.top() + offset.y();
			if (member.resizePart & Part_Right)
				rect.right() = rect.right() + offset.x();
			if (member.resizePart & Part_Bottom)
				rect.bottom() = rect.bottom() + offset.y();
			if (member.resizePart & Part_Title)
				rect.move(offset);
			this->setRect(rect);
			return;
		}

		BPoint pos = mouseEvent.pos();
		CursorType cursor = Cursor_None;
		bool hoverTitle = member.titleRect.contain(pos);
		if (member.hoverTitle != hoverTitle)
		{
			member.hoverTitle = hoverTitle;
			this->fresh();
		}
		member.resizePart = Part_None;
		if (member.hoverTitle)
		{
			member.resizePart = Part_Title;
		}
		if (member.borderLeft.contain(pos))
		{
			member.resizePart = Part_Left;
			cursor = Cursor_SizeHor;
		}
		if (member.borderRight.contain(pos))
		{
			member.resizePart = Part_Right;
			cursor = Cursor_SizeHor;
		}
		if (member.borderTop.contain(pos))
		{
			member.resizePart = Part_Top;
			cursor = Cursor_SizeVer;
		}
		if (member.borderBottom.contain(pos))
		{
			member.resizePart = Part_Bottom;
			cursor = Cursor_SizeVer;
		}
		if (!this->cursor() || this->cursor()->type() != cursor)
		{
			this->setCursor(cursor);
		}
	}
	BWidget::mouseMoveEvent(mouseEvent);
}

void BMainWindow::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (widget_member(this)->frameless)
	{
		member.pressed = false;
		BPoint pos = mouseEvent.pos();
	}
	BWidget::mouseClickEvent(mouseEvent);
}
void BMainWindow::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = false;
	if (!widget_member(this)->parent && widget_member(this)->frameless)
	{
		BPoint pos = mouseEvent.pos();
		Button button = mouseEvent.button();
		if (button == Button_Left && member.titleRect.contain(pos))
		{
			IWindow* window = widget_member(this)->window;
			if (window)
			{
				if (window->isMaximized())
					window->showNormal();
				else
					window->showMaximized();
			}
			BPixmap* pixmap = widget_member(this)->pixmap;
			if (pixmap)
			{
				BSize size = pixmap->size();
				if (this->width() > size.width() * 0.96 && this->height() > size.height() * 0.96)
				{
					this->setRect(member.normalRect);
				}
				else
				{
					member.normalRect = this->rect();
					this->setRect(0, 0, size.width(), size.height());
				}
			}
			member.dirty = true;
			this->fresh();
		}
	}
	BWidget::mouseDoubleClickEvent(mouseEvent);
}

